#include "TcpServer.h"
#include <functional>
#include <QDebug>

TcpServer::TcpServer()
{
    _thread = new QThread();
}

TcpServer::~TcpServer()
{
    Stop();
    if(_thread) {
        _thread->quit();
        _thread->wait();
    }
    delete _thread;
    _thread = nullptr;
}

bool TcpServer::Start(unsigned short port)
{
    if(_IsRun) return true;

#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
    bool ok = listen(QHostAddress::AnyIPv4, port);
#else
    bool ok = listen(QHostAddress::Any, port);
#endif

    _IsRun = ok;
    _thread->start();

    return ok;
}

bool TcpServer::IsStart()
{
    return _IsRun;
}

void TcpServer::Stop()
{
    if(_IsRun) {
        this->close();

        {
            std::lock_guard<std::mutex> lock(_mutex);
            for(auto &s : m_SessionVector) {
                std::shared_ptr<TcpSession> session = s.second;
                //先关已有连接, important
                if(session.get()) {
                    disconnect(session.get(), &TcpSession::SignalDisconnect, this, &TcpServer::SlotDisconnect);
                    //此处不能调用disconnect
                    session.get()->Disconnect();
                }
            }
        }

        m_SessionVector.clear();
        _IsRun = false;
    }
}

size_t TcpServer::GetSessionSize() const
{
    return m_SessionVector.size();
}

void TcpServer::incomingConnection(qintptr handle)
{
    std::shared_ptr<TcpSession> session = std::make_shared<TcpSession>();

    session->setSocketDescriptor(handle);
    session->setIPPort(session->peerAddress().toString(), session->peerPort());
    //Qt::QueuedConnection 防止shared_ptr内存溢出
    connect(session.get(), &TcpSession::SignalDisconnect, this, &TcpServer::SlotDisconnect, Qt::QueuedConnection);
    //connect(session.get(), &TcpSession::SignalDisconnect, this, &TcpServer::SlotDisconnect);

    {
        std::lock_guard<std::mutex> lock(_mutex);
        m_SessionVector[session->getIPPort().toStdString()] = session;
    }
    session->moveToThread(_thread);
    if(onAccepted)
        onAccepted(session);
}

void TcpServer::SlotDisconnect(const QString& session)
{
    std::lock_guard<std::mutex> lock(_mutex);

    std::string ss = session.toStdString();
    auto it = m_SessionVector.find(ss);
    if(it != m_SessionVector.end()) {
        m_SessionVector.erase(it);
        qDebug() << "TcpServer::SlotDisconnect";
    }
#if 0
    for(auto &s:m_SessionVector) {
        if(s.first == ss) {
            m_SessionVector.erase(ss);
            qDebug() << "TcpServer::SlotDisconnect";
            break;
        }
    }
#endif
}
